package com.jingge.autojob.skeleton.model.task.remote;

import com.google.gson.reflect.TypeToken;
import com.jingge.autojob.skeleton.framework.task.AutoJobRunResult;
import com.jingge.autojob.skeleton.framework.task.AutoJobRunningContextHolder;
import com.jingge.autojob.util.http.HttpUtil;
import com.jingge.autojob.util.json.JsonUtil;
import okhttp3.MediaType;
import okhttp3.Request;
import okhttp3.RequestBody;

import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author JingGe(* ^ ▽ ^ *)
 * @date 2023-09-05 16:17
 * @email 1158055613@qq.com
 */
public class BaseJsonHttpInterceptor implements RemoteTaskInterceptor {
    private static final String JSON_TYPE = "application/json;charset=UTF-8";
    private static final String USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.139 Safari/537.36";

    @Override
    public RequestHandler before(RemoteTask task) {
        Map<String, Object> queryParams = getQueryParams(task.getParams() != null && task.getParams().length == 1 ? task.getParams()[0] : null);
        if (task.isEnableSharding()) {
            queryParams = queryParams == null ? new HashMap<>() : queryParams;
            queryParams.put("currentSharding", AutoJobRunningContextHolder
                    .currentTaskContext()
                    .getCurrentSharding());
        }
        Request.Builder builder = HttpUtil
                .requestBuilder()
                .url(HttpUtil
                        .urlBuilder(queryParams)
                        .host(task.getHost())
                        .port(task.getPort())
                        .scheme(task
                                .getProtocolType()
                                .getType())
                        .addPathSegments(task.getUri())
                        .build());
        if (task.getBody() != null) {
            MediaType mediaType = MediaType.parse(JSON_TYPE);
            RequestBody requestBody = RequestBody.create(task.getBody() instanceof String ? (String) task.getBody() : JsonUtil.pojoToJsonString(task.getBody()), mediaType);
            builder.method(task.getReqType(), "GET".equalsIgnoreCase(task.getReqType()) ? null : requestBody);
        }
        configHeader(builder, getHeaders(task.getHeader()));
        return new BaseJsonHttpRequestHandler(builder.build(), task.getConnectTimeout(), task.getReadTimeout(), task.getWriteTimeout());
    }

    @Override
    public AutoJobRunResult after(RemoteTask task, RemoteResponse remoteResponse) {
        if (!(remoteResponse instanceof HttpRemoteResponse)) {
            return null;
        }
        try {
            return new AutoJobRunResult(remoteResponse.isSuccess(), remoteResponse.getAsString());
        } finally {
            ((HttpRemoteResponse) remoteResponse).close();
        }
    }

    @SuppressWarnings("unchecked")
    private Map<String, Object> getQueryParams(Object params) {
        if (params == null) {
            return null;
        }
        if (params instanceof Map) {
            return (Map<String, Object>) params;
        }
        if (params instanceof String) {
            try {
                return JsonUtil.jsonStringToMap((String) params, String.class, Object.class);
            } catch (Exception ignored) {
            }
        }
        return null;
    }

    @SuppressWarnings("unchecked")
    private Map<String, List<String>> getHeaders(Object headers) {
        if (headers == null) {
            return null;
        }
        if (headers instanceof Map) {
            return (Map<String, List<String>>) headers;
        }
        if (headers instanceof String) {
            try {
                Type mapType = new TypeToken<Map<String, List<String>>>() {
                }.getType();
                return JsonUtil.jsonString2Instance((String) headers, mapType);
            } catch (Exception ignored) {
            }
        }
        return null;
    }

    private void configHeader(Request.Builder builder, Map<String, List<String>> headers) {
        if (headers == null || builder == null) {
            return;
        }
        for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
            if (entry.getValue() == null) {
                continue;
            }
            for (String value : entry.getValue()) {
                builder.addHeader(entry.getKey(), value);
            }
        }
        if (!headers.containsKey("User-Agent")) {
            builder.addHeader("User-Agent", USER_AGENT);
        }
        if (!headers.containsKey("Connection")) {
            builder.addHeader("Connection", "keep-alive");
        }
        if (!headers.containsKey("Content-Type")) {
            builder.addHeader("Content-Type", JSON_TYPE);
        }
    }


}
